﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
/*作者:z
  2020/12/14
  参考资料：
  https://www.cnblogs.com/yangfengwu/p/12382103.html
 */
namespace GrillPower_Supply
{
    public partial class Form1 : Form
    {
        int online_flag = 0;//预留变量
        String serialPortName;
        /*
         * 通信协议数组
         */
        byte[] buf_start = { 0x01,0x06,0x00,0x09,0x00,0x01 };  //启动
        byte[] buf_stop = { 0x01, 0x06, 0x00, 0x09, 0x00, 0x00 };//暂停

        byte[] buf_get_V = { 0x01, 0x03, 0x00, 0x02, 0x00, 0x01 };//获取电压值
        byte[] buf_get_F = { 0x01, 0x03, 0x00, 0x01, 0x00, 0x01 };//获取输出频率
        byte[] buf_get_A = { 0x01, 0x03, 0x00, 0x03, 0x00, 0x01 };//获取输出电流
        byte[] buf_get_W = { 0x01, 0x03, 0x00, 0x04, 0x00, 0x01 };//获取输出功率

        byte[] buf_set_V = { 0x01, 0x06, 0x00, 0x08, 0x00, 0x00 };//设置电压值
        byte[] buf_set_F = { 0x01, 0x06, 0x00, 0x07, 0x00, 0x00 };//设置输出频率
        /// <summary>
        /// CRC16_Modbus效验
        /// </summary>
        /// <param name="byteData">要进行计算的字节数组</param>
        /// <returns>计算后的数组</returns>
        public static byte[] ToModbus(byte[] byteData)
        {
            byte[] CRC = new byte[2];

            UInt16 wCrc = 0xFFFF;
            for (int i = 0; i < byteData.Length; i++)
            {
                wCrc ^= Convert.ToUInt16(byteData[i]);
                for (int j = 0; j < 8; j++)
                {
                    if ((wCrc & 0x0001) == 1)
                    {
                        wCrc >>= 1;
                        wCrc ^= 0xA001;//异或多项式
                    }
                    else
                    {
                        wCrc >>= 1;
                    }
                }
            }

            CRC[1] = (byte)((wCrc & 0xFF00) >> 8);//高位在后
            CRC[0] = (byte)(wCrc & 0x00FF);       //低位在前
            return CRC;

        }
        public Form1()
        {
            InitializeComponent();
            Control.CheckForIllegalCrossThreadCalls = false;
        }
        /// <summary>   
        /// 获取本机所有ip地址（未用到，后期使用socket通信会用到）
        /// </summary>
        /// <param name="netType">"InterNetwork":ipv4地址，"InterNetworkV6":ipv6地址</param>
        /// <returns>ip地址集合</returns>
        public static List<string> GetLocalIpAddress(string netType)
        {
            string hostName = Dns.GetHostName();                    //获取主机名称
            IPAddress[] addresses = Dns.GetHostAddresses(hostName); //解析主机IP地址

            List<string> IPList = new List<string>();
            if (netType == string.Empty)
            {
                for (int i = 0; i < addresses.Length; i++)
                {
                    IPList.Add(addresses[i].ToString());
                }
            }
            else
            {
                //AddressFamily.InterNetwork表示此IP为IPv4,
                //AddressFamily.InterNetworkV6表示此地址为IPv6类型
                for (int i = 0; i < addresses.Length; i++)
                {
                    if (addresses[i].AddressFamily.ToString() == netType)
                    {
                        IPList.Add(addresses[i].ToString());
                    }
                }
            }
            return IPList;
        }
        /*
         * 界面加载 类似C语言里面的主函数，但是不等于是主函数
         */
        private void Form1_Load(object sender, EventArgs e)
        {
            //获取电脑当前可用串口并添加到选项列表中
            comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
            comboBox1.SelectedIndex = comboBox1.Items.Count > 0 ? 0 : -1;
            //将常用的电压和频率预存到列表中
            comboBox2.Items.Add("120");
            comboBox2.Items.Add("220");
            comboBox3.Items.Add("50");
            comboBox3.Items.Add("60");
            // List<string> ipv4_ips = GetLocalIpAddress("InterNetwork");

            try//在未连接到电源之前把一些控件都锁死
            {
                groupBox4.Enabled = false;
                groupBox2.Enabled = false;
                groupBox3.Enabled = false;
                button4.Enabled = false;
            }
            catch (Exception ex)//抛出异常  其实这里不需要这样做
            {
                //捕获可能发生的异常并进行处理
                //serialPort1.Close();
                //捕获到异常，创建一个新的对象，之前的不可以再用
                serialPort1 = new System.IO.Ports.SerialPort();
                //刷新COM口选项
                comboBox1.Items.Clear();
                comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
                //响铃并显示异常给用户
                System.Media.SystemSounds.Beep.Play();
                button1.Text = "连接";
                button1.BackColor = Color.ForestGreen;
                button1.BackColor = Color.Empty;
                MessageBox.Show(ex.Message);
                comboBox1.Enabled = true;
                groupBox4.Enabled = false;
                groupBox2.Enabled = false;
                groupBox3.Enabled = false;
                button4.Enabled = false;
                // comboBox2.Enabled = true;
            }

        }
        /*
         * 用来实现热插热拔
         */
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x0219)
            {//设备改变
                if (m.WParam.ToInt32() == 0x8004)
                {//usb串口拔出
                    string[] ports = System.IO.Ports.SerialPort.GetPortNames();//重新获取串口
                    comboBox1.Items.Clear();//清除comboBox里面的数据
                    comboBox1.Text = "";
                    comboBox1.Items.AddRange(ports);//给comboBox1添加数据
                    if (button1.Text == "连接成功")
                    {//用户打开过串口
                        if (!serialPort1.IsOpen)
                        {//用户打开的串口被关闭:说明热插拔是用户打开的串口
                            button1.Text = "连接";
                            serialPort1.Dispose();//释放掉原先的串口资源
                            comboBox1.SelectedIndex = comboBox1.Items.Count > 0 ? 0 : -1;//显示获取的第一个串口号
                        }
                        else
                        {
                            comboBox1.Text = serialPortName;//显示用户打开的那个串口号
                        }
                    }
                    else
                    {//用户没有打开过串口
                        comboBox1.SelectedIndex = comboBox1.Items.Count > 0 ? 0 : -1;//显示获取的第一个串口号
                    }
                    
                }
                else if (m.WParam.ToInt32() == 0x8000)
                {//usb串口连接上
                    string[] ports = System.IO.Ports.SerialPort.GetPortNames();//重新获取串口
                    comboBox1.Items.Clear();
                    comboBox1.Items.AddRange(ports);
                    if (button1.Text == "连接成功")
                    {//用户打开过一个串口
                        comboBox1.Text = serialPortName;//显示用户打开的那个串口号
                    }
                    else
                    {
                        comboBox1.SelectedIndex = comboBox1.Items.Count > 0 ? 0 : -1;//显示获取的第一个串口号
                    }
                }
            }
            base.WndProc(ref m);
        }
        /*
         * 连接按钮的单击事件
         */
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                if (serialPort1.IsOpen)//串口是否已经打开
                {
                    serialPort1.Close();    //关闭串口
                    button1.Text = "连接";
                    button1.BackColor = Color.Empty;
                    comboBox1.Enabled = true;
                    label4.Text = "断开连接";
                    label4.ForeColor = Color.Red;
                    groupBox2.Enabled = false;
                    groupBox3.Enabled = false;
                    groupBox4.Enabled = false;
                    button4.Enabled = false;
                    timer1.Stop();     //启动定时器
                    //comboBox2.Enabled = true;
                }
                else
                {
                    //串口已经处于关闭状态，则设置好串口属性后打开
                    comboBox1.Enabled = false;
                    //groupBox2.Enabled = false;
                    groupBox3.Enabled = true;
                    groupBox4.Enabled = true;
                    button4.Enabled = true;
                    //comboBox2.Enabled = false;
                    serialPortName = comboBox1.Text;
                    serialPort1.PortName = comboBox1.Text;
                    serialPort1.BaudRate =9600;
                    //serialPort1.DataBits = Convert.ToInt16(comboBox3.Text);
                    serialPort1.Parity = System.IO.Ports.Parity.None;//
                    serialPort1.StopBits = System.IO.Ports.StopBits.One;
                    //serialPort1.ReceivedBytesThreshold = 1;
                    serialPort1.Open();     //打开串口
                    button1.Text = "连接成功";
                    button1.BackColor = Color.ForestGreen;
                    timer1.Interval = 500;     //定时器赋初值
                    timer1.Start();     //启动定时器
                    timer2.Interval = 3000;     //定时器赋初值
                    timer2.Start();     //启动定时器
                }
            }
            catch (Exception ex)
            {
                //捕获可能发生的异常并进行处理

                //捕获到异常，创建一个新的对象，之前的不可以再用
                serialPort1 = new System.IO.Ports.SerialPort();
                //刷新COM口选项
                comboBox1.Items.Clear();
                comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
                //响铃并显示异常给用户
                System.Media.SystemSounds.Beep.Play();
                button1.Text = "连接";
                button1.BackColor = Color.ForestGreen;
                button1.BackColor = Color.Empty;
                MessageBox.Show(ex.Message);
                comboBox1.Enabled = true;
                groupBox2.Enabled = false;
                groupBox3.Enabled = false;
                groupBox4.Enabled = false;
                // comboBox2.Enabled = true;
            }
        }
        /*
         * 串口接收函数，这里类似单片机内的串口中断服务函数
         */
        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            int frequency = 0;
            int Voltage = 0;
            int electric_current = 0;
            int power = 0;
            label4.Text = "电源在线";
            label4.ForeColor = Color.Green;
            byte[] received_buf = new byte[20];    //声明一个大小为num的字节数据用于存放读出的byte型数据
            serialPort1.Read(received_buf, 0, 20);   //读取接收缓冲区中num个字节到byte数组中

            if (received_buf[1]==0x03 && received_buf[2] == 12) {
                if (received_buf[4] == 0) { label9.Text = "待机状态"; label9.ForeColor = Color.Green; }
                else if (received_buf[4] == 1) { label9.Text = "运行状态"; label9.ForeColor = Color.Red; }
                else { label9.Text = "其他状态"; }
                //做一些显示的处理
                frequency = received_buf[5] << 8 | received_buf[6];
                label6.Text = "频率:" + frequency * 0.1 + " Hz";
                Voltage = received_buf[7] << 8 | received_buf[8];
                label5.Text = "电压:" + Voltage * 0.1 + " V";
                electric_current = received_buf[9] << 8 | received_buf[10];
                label7.Text = "电流:" + electric_current * 0.001 + " A";
                power = received_buf[11] << 8 | received_buf[12];
                label8.Text = "功率:" + power * 0.1 + " W";
            }
            if (received_buf[1] == 0x06 && received_buf[3] == 7 )
            {
                label14.Text = "设置成功";
                //groupBox2.Enabled = false;
            }
            if (received_buf[1] == 0x06 && received_buf[3] == 8)
            {
                label13.Text = "设置成功";
                //groupBox2.Enabled = false;
            }

        }
        /*
         * 定时器1 500ms运行一次
         */
        private void timer1_Tick(object sender, EventArgs e)
        {
            //byte[] sendBuf = new byte[buf_get_V.Length + 2];
            byte[] buf_get_all = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x06 };
            byte[] sendBuf = new byte[buf_get_all.Length + 2];
            for (int i = 0; i < buf_get_all.Length; i++)
            {
                sendBuf[i] = buf_get_all[i];
            }
            sendBuf[buf_get_all.Length + 0] = ToModbus(buf_get_all)[0];
            sendBuf[buf_get_all.Length + 1] = ToModbus(buf_get_all)[1];
            try
            {
                serialPort1.Write(sendBuf, 0, sendBuf.Length);
            }
            catch (Exception ex)
            {
                timer1.Stop();
               // comboBox1.Enabled = true;
            }
                
           // t++;
            //if (t > 3) t = 0;
        }
        /*
         * 启动按钮单击事件
         * 发送启动电源指令
         */
        private void button2_Click(object sender, EventArgs e)
        {
            byte[] sendBuf = new byte[buf_start.Length+2];
            for (int i=0;i< buf_start.Length;i++) {
                sendBuf[i]= buf_start[i];
            }
            sendBuf[buf_start.Length + 0] =ToModbus(buf_start)[0];
            sendBuf[buf_start.Length + 1] = ToModbus(buf_start)[1];
            serialPort1.Write(sendBuf, 0, sendBuf.Length);  //循环发送
        }

        /*
         * 暂停按钮单击事件
         * 发送停止电源指令
         */
        private void button3_Click(object sender, EventArgs e)
        {
            byte[] sendBuf = new byte[buf_stop.Length + 2];
            for (int i = 0; i < buf_start.Length; i++)
            {
                sendBuf[i] = buf_stop[i];
            }
            sendBuf[buf_stop.Length + 0] = ToModbus(buf_stop)[0];
            sendBuf[buf_stop.Length + 1] = ToModbus(buf_stop)[1];
            serialPort1.Write(sendBuf, 0, sendBuf.Length); 
        }
        /*
         * 解锁设置按钮单击时间
         * 防止误操作导致毁坏电路板
         */
        private void button4_Click(object sender, EventArgs e)
        {

            if (groupBox2.Enabled)
            {
                groupBox2.Enabled = false;
                button4.Text = "解锁设置";
                //button5.Text = "设置";
                label13.Text = "";
                label14.Text = "";
            }
            else {
                groupBox2.Enabled = true;
                button4.Text = "锁定设置";
                //button5.Text = "设置";
            }
        }
        /*
         * 电压设置按钮单击事件
         */
        private void button5_Click(object sender, EventArgs e)
        {
            try {
                int V = int.Parse(comboBox2.Text) * 10;
               // int F = int.Parse(comboBox3.Text) * 10;

                int V_H = (V & 0xff00)>>8;
                int V_L = V & 0x00ff;
               

                /*设置电压*/
                byte[] sendBuf = new byte[buf_set_V.Length + 2];
                buf_set_V[buf_set_V.Length - 2] = (byte)V_H;
                buf_set_V[buf_set_V.Length - 1] = (byte)V_L;
                for (int i = 0; i < buf_set_V.Length; i++)
                {
                    sendBuf[i] = buf_set_V[i];
                }
                sendBuf[buf_set_V.Length + 0] = ToModbus(buf_set_V)[0];
                sendBuf[buf_set_V.Length + 1] = ToModbus(buf_set_V)[1];
                serialPort1.Write(sendBuf, 0, sendBuf.Length);

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }


        }
        /*
         * 频率设置按钮单击事件
         */
        private void button6_Click(object sender, EventArgs e)
        {

            try
            {
                int F = int.Parse(comboBox3.Text) * 10;
                int F_H = (F & 0xff00) >> 8;
                int F_L = F & 0x00ff;
                byte[] sendBuf = new byte[buf_set_F.Length + 2];
                /*设置频率*/
                buf_set_F[buf_set_F.Length - 2] = (byte)F_H;
                buf_set_F[buf_set_F.Length - 1] = (byte)F_L;
                for (int i = 0; i < buf_set_F.Length; i++)
                {
                    sendBuf[i] = buf_set_F[i];
                }
                sendBuf[buf_set_F.Length + 0] = ToModbus(buf_set_F)[0];
                sendBuf[buf_set_F.Length + 1] = ToModbus(buf_set_F)[1];
                serialPort1.Write(sendBuf, 0, sendBuf.Length);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            label13.Text = "";
            label14.Text = "";
        }
    }
}
